package cn.com.cym.gamezao.service.grk.impl;

import cn.com.cym.gamezao.base.BaseImpl;
import cn.com.cym.gamezao.base.BaseRepository;
import cn.com.cym.gamezao.base.ResultResponse;
import cn.com.cym.gamezao.base.SearchPage;
import cn.com.cym.gamezao.dto.DiagnoseDto;
import cn.com.cym.gamezao.dto.DiagnoseExportDto;
import cn.com.cym.gamezao.dto.DiagnoseSearchDto;
import cn.com.cym.gamezao.entity.grk.Diagnose;
import cn.com.cym.gamezao.entity.grk.Sample;
import cn.com.cym.gamezao.exception.BaseException;
import cn.com.cym.gamezao.jwt.RequestUser;
import cn.com.cym.gamezao.repository.grk.DiagnoseRepository;
import cn.com.cym.gamezao.repository.grk.SampleRepository;
import cn.com.cym.gamezao.service.grk.DiagnoseService;
import cn.com.cym.gamezao.util.CommonUtils;
import cn.hutool.core.util.ReflectUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@AllArgsConstructor
@Service
@Transactional(rollbackFor = Exception.class)
public class DiagnoseImpl extends BaseImpl<Diagnose> implements DiagnoseService {

    final DiagnoseRepository thisRepository;

    final SampleRepository sampleRepository;

    final EntityManager entityManager;

    @Override
    public BaseRepository<Diagnose, Long> getJpaRepository() {
        return thisRepository;
    }

    @Override
    public Page<Diagnose> findByPageable(SearchPage searchPage) {
        String[] sortBy = searchPage.getSortBy().toArray(new String[searchPage.getSortBy().size()]);

        Pageable pageable = PageRequest.of(searchPage.getCurrent()-1, searchPage.getPageSize(), searchPage.getSort(), sortBy);

        Specification<Diagnose> specification = new Specification<>() {

            private static final long serialVersionUID = -2661077778894635593L;

            @SneakyThrows
            @Override
            public Predicate toPredicate(Root<Diagnose> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                final Map<String, Field> fieldMap = ReflectUtil.getFieldMap(Diagnose.class);
                return cb.and(CommonUtils.pageSet(fieldMap,searchPage,cb,root));
            }
        };
        return this.thisRepository.findAll(specification, pageable);
    }

    /**
     * 重新报错逻辑
     * @param diagnose diagnose
     * @return Diagnose
     */
    @Override
    public Diagnose save(Diagnose diagnose) {
        super.save(diagnose);
        if(diagnose.getSamples().size()>0){
            for(Sample sample:diagnose.getSamples()){
                sample.setDiagnose(diagnose);
                if(sample.getId()!=null){
                    sample.setCreateUserId(RequestUser.get().getId());
                    sample.setCreateTime(LocalDateTime.now());
                }
                sample.setModifyUserId(RequestUser.get().getId());
                sample.setModifyTime(LocalDateTime.now());
                sampleRepository.save(sample);
            }
        }
        return diagnose;
    }

    @Override
    public List<DiagnoseExportDto> getAllBySearchPage(DiagnoseSearchDto searchPage) {

        StringBuffer sb= new StringBuffer(" select t.reg_num as regNum,t.name,s.code as sampleNo,s.position,DATE_FORMAT(e.diagnose_time, '%Y-%m-%d') as diagnoseTime," +
                "e.medicine,e.diagnose_id as diagnoseId \n" +
                " from sample_diagnose e left join  sample_patient t on e.patient_id =t.id  left join  sample_sample s on e.id = s.diagnose_id \n" +
                "  where  1=1");
        if(searchPage.getDiagnoseTimes()!=null && searchPage.getDiagnoseTimes().size()==2){
            if(searchPage.getDiagnoseTimes().get(0).compareTo(searchPage.getDiagnoseTimes().get(1))>0){
                throw new BaseException("未选择时间区域", new ResultResponse("未选择时间区域", HttpStatus.BAD_REQUEST.value()));
            }
            sb.append(" and (e.diagnose_time between '")
                    .append(searchPage.getDiagnoseTimes().get(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                    .append("' and '").append(searchPage.getDiagnoseTimes().get(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                    .append("') ");
        }
        boolean flag = true;
        // 诊断用逗号分割
        if(CommonUtils.isNotEmpty(searchPage.getDiagnoseId())){
            String[] split = searchPage.getDiagnoseId().split(",");
            sb.append(" and (");
            for(String diagnose :split){
                sb.append(" e.diagnose_id like '%").append(diagnose).append("%' ");
                if(!diagnose.equals(split[split.length-1])){
                    sb.append(" or ");
                }
            }
            sb.append(" )");
            flag = false;
        }

        /**
         * 诊断条件只能出现一次
         */
        if(CommonUtils.isNotEmpty(searchPage.getDiagnoses()) && flag){
            String[] split = searchPage.getDiagnoses().split(",");
            sb.append(" and (");
            for(String diagnose :split){
                // find_in_set 函数用于查询带有逗号的多选
                sb.append(" find_in_set('").append(diagnose).append("',e.diagnose_id) ");
                if(!diagnose.equals(split[split.length-1])){
                    sb.append(" or ");
                }
            }
            sb.append(" )");
        }
        if(CommonUtils.isNotEmpty(searchPage.getPastHis())){
            sb.append(" and  e.past_his like '%").append(searchPage.getPastHis()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getNowHis())){
            sb.append(" and  e.now_his like '%").append(searchPage.getNowHis()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getMedicine())){
            sb.append(" and  e.medicine like '%").append(searchPage.getMedicine()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getName())){
            sb.append(" and  t.name like '%").append(searchPage.getName()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getRegNum())){
            sb.append(" and  t.reg_num like '%").append(searchPage.getRegNum()).append("%' ");
        }

        //String sql = "";

        System.out.println(sb);
        NativeQueryImpl query = entityManager.createNativeQuery(sb.toString()).unwrap(NativeQueryImpl.class);
        //final Query query = //query;
        query.setResultTransformer(Transformers.aliasToBean(DiagnoseExportDto.class));

        List<DiagnoseExportDto> resultList = query.getResultList();

        return resultList;
    }
    public DiagnoseDto getDtoById(Long id) {
        Diagnose diagnose = super.fetchOne(id);
        DiagnoseDto dto = new DiagnoseDto();
        BeanUtils.copyProperties(diagnose,dto);
        List<Sample> allByDiagnose = sampleRepository.getAllByDiagnose(diagnose);
        dto.setSamples(allByDiagnose);
        return dto;
    }

    @Override
    public Page<Diagnose> findPageBySearchDto(DiagnoseSearchDto searchPage) {


        StringBuffer countSql= new StringBuffer("select count(1) ");
        StringBuffer dataSql = new StringBuffer("select e.* ");
        StringBuffer sb= new StringBuffer(" from sample_diagnose e left join  sample_patient t on e.patient_id =t.id \n" +
                "  where  1=1 ");
        if(searchPage.getDiagnoseTimes()!=null && searchPage.getDiagnoseTimes().size()==2){
            if(searchPage.getDiagnoseTimes().get(0).compareTo(searchPage.getDiagnoseTimes().get(1))>0){
                throw new BaseException("未选择时间区域", new ResultResponse("未选择时间区域", HttpStatus.BAD_REQUEST.value()));
            }
            sb.append(" and (e.diagnose_time between '")
                    .append(searchPage.getDiagnoseTimes().get(0).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                    .append("' and '").append(searchPage.getDiagnoseTimes().get(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                    .append("') ");
        }
        boolean flag = true;
        // 诊断用逗号分割
        if(CommonUtils.isNotEmpty(searchPage.getDiagnoseId())){
            String[] split = searchPage.getDiagnoseId().split(",");
            sb.append(" and (");
            for(String diagnose :split){
                sb.append(" e.diagnose_id like '%").append(diagnose).append("%' ");
                if(!diagnose.equals(split[split.length-1])){
                    sb.append(" or ");
                }
            }
            sb.append(" )");
            flag = false;
        }
        // 诊断条件只能出现一次

        if(CommonUtils.isNotEmpty(searchPage.getDiagnoses()) && flag){
            String[] split = searchPage.getDiagnoses().split(",");
            sb.append(" and (");
            for(String diagnose :split){
                // find_in_set 函数用于查询带有逗号的多选
                sb.append(" find_in_set('").append(diagnose).append("',e.diagnose_id) ");
                if(!diagnose.equals(split[split.length-1])){
                    sb.append(" or ");
                }
            }
            sb.append(" )");
        }
        if(CommonUtils.isNotEmpty(searchPage.getPastHis())){
            sb.append(" and  e.past_his like '%").append(searchPage.getPastHis()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getNowHis())){
            sb.append(" and  e.now_his like '%").append(searchPage.getNowHis()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getMedicine())){
            sb.append(" and  e.medicine like '%").append(searchPage.getMedicine()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getName())){
            sb.append(" and  t.name like '%").append(searchPage.getName()).append("%' ");
        }
        if(CommonUtils.isNotEmpty(searchPage.getRegNum())){
            sb.append(" and  t.reg_num like '%").append(searchPage.getRegNum()).append("%' ");
        }

        System.out.println(sb);
        dataSql.append(sb).append(" limit "+ (searchPage.getCurrent()-1)* searchPage.getPageSize() +", "+ searchPage.getPageSize());
        final Query query = entityManager.createNativeQuery(dataSql.toString(),Diagnose.class);


        Query countQuery = entityManager.createNativeQuery(countSql.append(sb).toString());
        BigInteger totalCount = (BigInteger)countQuery.getSingleResult();
        String[] sortBy = searchPage.getSortBy().toArray(new String[searchPage.getSortBy().size()]);

        Pageable pageable = PageRequest.of(searchPage.getCurrent()-1, searchPage.getPageSize(), searchPage.getSort(), sortBy);

        List<Diagnose> resultList = query.getResultList();
        Page<Diagnose> page = new PageImpl<>(resultList,pageable,totalCount.longValue());
        return page;
    }
}
